package com.shiliuzi.www.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.shiliuzi.www.common.Code;
import com.shiliuzi.www.exception.GlobalException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;

import static jdk.nashorn.internal.runtime.regexp.joni.Config.log;

@Slf4j
@Component
public class CommonUtil {

    private static final ObjectMapper mapper = new ObjectMapper();

    private static final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
            1000,
            1000,
            2000l,
            TimeUnit.MILLISECONDS,
            new ArrayBlockingQueue<Runnable>(75,true));

    /**
     * 随机验证码
     * @return
     */
    public Integer randomCode() {
        return (int) (Math.random()*1000000);
    }

    /**
     * 对象转换Map器
     * @param target
     * @return
     */
    public Map<String,Object> mapConverter (Object target) {
        try {
            Map<String,Object> returnMap = new HashMap<>();

            Class className = target.getClass();

            Field[] fields = className.getDeclaredFields();
            for (Field field : fields) {
                if(Modifier.isFinal(field.getModifiers())) continue;
                String fieldName = field.getName();
                Method getFieldMethod = className.getMethod("get" +
                        fieldName.substring(0,1).toUpperCase() +
                        fieldName.substring(1));
                returnMap.put(fieldName,getFieldMethod.invoke(target));
            }

            return returnMap;
        } catch (Exception e) {
            throw new GlobalException(Code.ERROR, "系统内部出错！对象转Map器出错！");
        }
    }

    /**
     * Map转换对象器
     * @param map
     * @param target
     * @param <T>
     * @return
     */
    public <T> T objectConverter (Map map, Class<T> target) {
        try {
            T returnObject = target.newInstance();

            Field[] fields = target.getDeclaredFields();
            for (Field field : fields) {
                //获取参数名
                if(Modifier.isFinal(field.getModifiers())) continue;
                String fieldName = field.getName();
                Class fieldType = field.getType();

                //获取设置方法
                Method getFieldMethod = target.getMethod("set" +
                        fieldName.substring(0,1).toUpperCase() +
                        fieldName.substring(1),fieldType);

                getFieldMethod.invoke(returnObject,map.get(fieldName));
            }

            return returnObject;
        } catch (Exception e) {
            throw new GlobalException(Code.SYS_ERR,"系统内部出错！Map转换对象器宕机！");
        }
    }

    /**
     * 传参转换器
     * @param source
     * @param targetClass
     * @param <T>
     * @return
     */
    public <T> T copyProperties(Object source, Class<T> targetClass) {

        if (source == null) return null;

        try {
            T target = targetClass.newInstance();

            Field[] fields = targetClass.getDeclaredFields();
            for (Field field : fields) {
                if (Modifier.isFinal(field.getModifiers())) continue;
                String fieldName = field.getName();
                String methodSuffix = fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);

                if (!propertiesField(source.getClass(),fieldName)) continue;

                //获取类型
                Class targetField = field.getType();
                Class sourceField = source.getClass().getDeclaredField(fieldName).getType();

                //获取资源方法
                Method sourceMethod = source.getClass().getMethod("get" + methodSuffix);
                String targetMethodName = "set" + methodSuffix;
                Method targetMethod = null;

                if (!targetField.equals(sourceField)) targetMethod = targetClass.getMethod(targetMethodName, sourceField);
                else targetMethod = targetClass.getMethod(targetMethodName, targetField);

                //执行目标方法
                targetMethod.invoke(target,sourceMethod.invoke(source));
            }

            return target;

        } catch (Exception e) {
            throw new GlobalException(Code.SYS_ERR,"系统内部出错！传参转换器宕机！");
        }
    }

    /**
     * 查询资源类是否有相应字段
     * @param source
     * @param fieldName
     * @return
     */
    public <T> boolean propertiesField(Class<T> source, String fieldName) {
        Field[] fields = source.getDeclaredFields();

        for (Field field : fields) {
            if (fieldName.equals(field.getName())) return true;
        }

        return false;
    }

    /**
     * 集合对象转换器
     * @param source
     * @param className
     * @param <T>
     * @param <R>
     * @return
     */
    public <T,R> List<T> copyPropertiesList(List<R> source, Class<T> className) {
        if(source == null || source.size() == 0) return null;

        List target = new ArrayList();
        try {
            source.forEach((value)->{
                T targetSingle = copyProperties(value, className);
                target.add(targetSingle);
            });

        } catch (Exception e) {
            throw new GlobalException(Code.SYS_ERR,"系统内部出错！集合对象转换器宕机！");
        }

        return target;
    }

    /**
     * 刷新时间转换器
     * @param nowDate
     * @param timeout
     * @return
     */
    public Date expireDate(Date nowDate, Long timeout) {
        Date returnDate = new Date();
        returnDate.setTime(nowDate.getTime() + 1000*timeout);
        System.out.println(returnDate);
        return returnDate;
    }

    /**
     * 限制器计算器
     * @param sum 总和
     * @param limit 限制页数
     * @param outOrIn 四舍五入，true为有余则加，false为有余不处理
     * @return
     */
    public Integer limitCalculate(Integer sum, Integer limit, boolean outOrIn) {

        Integer integerPart = sum / limit;
        Integer decimalPart = sum % limit;

        if(!decimalPart.equals(0) && outOrIn) return integerPart + 1;
        return integerPart;
    }

    /**
     * 线程操作器
     * @param runnable
     * @return
     */
    public void obtainThread(Runnable runnable) {
        threadPool.execute(()->{
            try {
                runnable.run();
            } catch (Exception e) {
                log.warn("{}线程执行出错！请稍后重试！",Thread.currentThread().getId());
            }
        });
    }

    /**
     * 线程调休器
     * @param threadId
     * @param time
     */
    public void sleepThread(@NotNull Long threadId, @Nullable Long time) {
        try {
            if(time==null) time=30l;
            log.info("线程{}休息{}s",threadId,time);
            Thread.sleep(time*1000);
        } catch (Exception e) {
            throw new GlobalException(Code.SYS_ERR,"系统内部出错！线程调休器出错！");
        }
    }

    /**
     * json转对象转换器
     * @param target
     * @param className
     * @param <T>
     * @return
     */
    public <T> T jsonReader(String target, Class<T> className) {
        try {
            return mapper.readValue(target,className);
        } catch (Exception e) {
            log.warn("无法将json{}转为{}",target,className);
            return null;
        }
    }

    /**
     * 对象转json转换器
     * @param target
     * @return
     */
    public String jsonWriter(Object target) {
        try {
            return mapper.writeValueAsString(target);
        } catch (Exception e) {
            log.warn("无法将{}转为json",target);
            return null;
        }
    }
}

